ปลดล็อกประสิทธิภาพเว็บที่เร็วยิ่งขึ้น เรียนรู้วิธีวิเคราะห์การคำนวณเลย์เอาต์ของ CSS Grid, วิเคราะห์ผลกระทบจากการปรับขนาด track และปรับปรุงไปป์ไลน์การเรนเดอร์ของคุณด้วย Chrome DevTools
การวิเคราะห์ประสิทธิภาพการปรับขนาด Track ของ CSS Grid: การเจาะลึกการวิเคราะห์การคำนวณ Layout
CSS Grid ได้ปฏิวัติการจัดวางเลย์เอาต์บนเว็บ โดยมอบพลังและความยืดหยุ่นที่ไม่เคยมีมาก่อนสำหรับการสร้างดีไซน์ที่ซับซ้อนและตอบสนองต่ออุปกรณ์ต่างๆ (responsive) ด้วยฟีเจอร์อย่างหน่วย `fr`, `minmax()` และการปรับขนาดตามเนื้อหา (content-aware sizing) เราสามารถสร้างอินเทอร์เฟซที่ครั้งหนึ่งเคยเป็นเพียงความฝันได้ ซึ่งบ่อยครั้งใช้โค้ดน้อยอย่างน่าประหลาดใจ อย่างไรก็ตาม พลังที่ยิ่งใหญ่มาพร้อมกับความรับผิดชอบที่ใหญ่ยิ่ง และในโลกของประสิทธิภาพเว็บ ความรับผิดชอบนั้นอยู่ที่การทำความเข้าใจต้นทุนทางการคำนวณของตัวเลือกในการออกแบบของเรา
ในขณะที่เรามักจะมุ่งเน้นไปที่การปรับปรุงประสิทธิภาพการทำงานของ JavaScript หรือการโหลดรูปภาพ แต่คอขวดด้านประสิทธิภาพที่สำคัญและมักถูกมองข้ามคือขั้นตอนการคำนวณเลย์เอาต์ของเบราว์เซอร์ ทุกครั้งที่เบราว์เซอร์ต้องการกำหนดขนาดและตำแหน่งขององค์ประกอบต่างๆ บนหน้าเว็บ มันจะดำเนินการที่เรียกว่า 'Layout' CSS ที่ซับซ้อน โดยเฉพาะอย่างยิ่งกับโครงสร้างกริดที่สลับซับซ้อน สามารถทำให้กระบวนการนี้มีค่าใช้จ่ายในการคำนวณสูง นำไปสู่การโต้ตอบที่เชื่องช้า การเรนเดอร์ที่ล่าช้า และประสบการณ์ผู้ใช้ที่ไม่ดี นี่คือจุดที่การวิเคราะห์ประสิทธิภาพไม่ได้เป็นเพียงเครื่องมือสำหรับการดีบัก แต่เป็นส่วนสำคัญของกระบวนการออกแบบและพัฒนา
คู่มือฉบับสมบูรณ์นี้จะพาคุณเจาะลึกสู่โลกแห่งประสิทธิภาพของ CSS Grid เราจะก้าวข้ามไวยากรณ์และสำรวจ 'เหตุผล' ที่อยู่เบื้องหลังความแตกต่างด้านประสิทธิภาพ คุณจะได้เรียนรู้วิธีใช้เครื่องมือสำหรับนักพัฒนาในเบราว์เซอร์เพื่อวัดผล วิเคราะห์ และวินิจฉัยคอขวดของเลย์เอาต์ที่เกิดจากกลยุทธ์การปรับขนาด track ของกริดของคุณ ในตอนท้าย คุณจะพร้อมที่จะสร้างเลย์เอาต์ที่ไม่เพียงแต่สวยงามและตอบสนองได้ดี แต่ยังรวดเร็วปานสายฟ้าอีกด้วย
ทำความเข้าใจไปป์ไลน์การเรนเดอร์ของเบราว์เซอร์
ก่อนที่เราจะสามารถปรับปรุงประสิทธิภาพได้ เราต้องเข้าใจกระบวนการที่เราพยายามจะปรับปรุงก่อน เมื่อเบราว์เซอร์เรนเดอร์หน้าเว็บ มันจะทำตามลำดับขั้นตอนที่มักเรียกว่า Critical Rendering Path แม้ว่าคำศัพท์เฉพาะทางอาจแตกต่างกันเล็กน้อยในแต่ละเบราว์เซอร์ แต่ขั้นตอนหลักโดยทั่วไปจะสอดคล้องกัน:
- Style: เบราว์เซอร์จะแยกวิเคราะห์ CSS และกำหนดสไตล์สุดท้ายสำหรับองค์ประกอบ DOM แต่ละรายการ ซึ่งเกี่ยวข้องกับการแก้ไข selectors, การจัดการ cascade และการคำนวณสไตล์ที่คำนวณได้สำหรับทุกโหนด
- Layout (or Reflow): นี่คือจุดที่เราให้ความสำคัญหลัก หลังจากคำนวณสไตล์แล้ว เบราว์เซอร์จะคำนวณรูปทรงเรขาคณิตของแต่ละองค์ประกอบ มันจะคำนวณว่าแต่ละองค์ประกอบควรไปอยู่ที่ไหนบนหน้าเว็บและใช้พื้นที่เท่าใด มันสร้าง 'layout tree' หรือ 'render tree' ที่มีข้อมูลทางเรขาคณิต เช่น ความกว้าง ความสูง และตำแหน่ง
- Paint: ในขั้นตอนนี้ เบราว์เซอร์จะเติมพิกเซล มันนำ layout tree จากขั้นตอนก่อนหน้ามาเปลี่ยนเป็นชุดของพิกเซลบนหน้าจอ ซึ่งรวมถึงการวาดข้อความ สี รูปภาพ เส้นขอบ และเงา โดยพื้นฐานแล้วคือส่วนที่มองเห็นได้ทั้งหมดขององค์ประกอบ
- Composite: เบราว์เซอร์จะวาดเลเยอร์ต่างๆ ที่ถูก paint ไว้ขึ้นบนหน้าจอตามลำดับที่ถูกต้อง องค์ประกอบที่ซ้อนทับกันหรือมีคุณสมบัติเฉพาะ เช่น `transform` หรือ `opacity` มักจะถูกจัดการในเลเยอร์ของตัวเองเพื่อปรับปรุงประสิทธิภาพการอัปเดตในภายหลัง
เหตุใดขั้นตอน 'Layout' จึงสำคัญต่อประสิทธิภาพของกริด
ขั้นตอน Layout สำหรับเอกสารแบบ block-and-inline ทั่วไปนั้นค่อนข้างตรงไปตรงมา เบราว์เซอร์มักจะสามารถประมวลผลองค์ประกอบต่างๆ ได้ในรอบเดียว โดยคำนวณขนาดของมันตามองค์ประกอบแม่ อย่างไรก็ตาม CSS Grid นำเสนอความซับซ้อนในระดับใหม่ คอนเทนเนอร์ของกริดเป็นระบบที่ทำงานตามข้อจำกัด (constraint-based system) ขนาดสุดท้ายของ track หรือ item ในกริดมักจะขึ้นอยู่กับขนาดของ track อื่นๆ, พื้นที่ว่างในคอนเทนเนอร์ หรือแม้กระทั่งขนาดที่แท้จริงของเนื้อหาภายใน item ที่อยู่ข้างเคียง
Layout engine ของเบราว์เซอร์ต้องแก้ระบบสมการที่ซับซ้อนนี้เพื่อให้ได้เลย์เอาต์สุดท้าย วิธีที่คุณกำหนด track ของกริด—ตัวเลือกหน่วยและฟังก์ชันการปรับขนาดของคุณ—ส่งผลโดยตรงต่อความยากลำบาก และดังนั้นจึงส่งผลต่อเวลาที่ต้องใช้ในการแก้ระบบนี้ นี่คือเหตุผลที่การเปลี่ยนแปลงเล็กน้อยใน `grid-template-columns` สามารถส่งผลกระทบอย่างไม่สมส่วนต่อประสิทธิภาพการเรนเดอร์
กายวิภาคของการปรับขนาด Track ใน CSS Grid: มุมมองด้านประสิทธิภาพ
เพื่อที่จะวิเคราะห์ประสิทธิภาพได้อย่างมีประสิทธิผล คุณจำเป็นต้องเข้าใจคุณลักษณะด้านประสิทธิภาพของเครื่องมือที่คุณมี มาดูรายละเอียดของกลไกการปรับขนาด track ที่พบบ่อยและวิเคราะห์ต้นทุนการคำนวณที่อาจเกิดขึ้น
1. การปรับขนาดแบบคงที่และคาดเดาได้ (Static and Predictable Sizing)
นี่คือตัวเลือกที่ง่ายที่สุดและมีประสิทธิภาพสูงสุด เนื่องจากมันให้ข้อมูลที่ชัดเจนและไม่คลุมเครือแก่ layout engine
- หน่วยคงที่ (`px`, `rem`, `em`): เมื่อคุณกำหนด track เป็น `grid-template-columns: 200px 10rem;` เบราว์เซอร์จะทราบขนาดที่แน่นอนของ track เหล่านี้ทันที ไม่จำเป็นต้องมีการคำนวณที่ซับซ้อน ซึ่งมีต้นทุนการคำนวณที่ถูกมาก
- หน่วยเปอร์เซ็นต์ (`%`): เปอร์เซ็นต์จะถูกคำนวณเทียบกับขนาดของคอนเทนเนอร์กริด แม้ว่าจะต้องมีขั้นตอนเพิ่มเติมหนึ่งขั้น (การดึงความกว้างของแม่) แต่มันก็ยังเป็นการคำนวณที่รวดเร็วและกำหนดผลลัพธ์ได้แน่นอน เบราว์เซอร์สามารถหาขนาดเหล่านี้ได้ตั้งแต่เนิ่นๆ ในกระบวนการ layout
โปรไฟล์ประสิทธิภาพ: เลย์เอาต์ที่ใช้เฉพาะการปรับขนาดแบบคงที่และแบบเปอร์เซ็นต์มักจะรวดเร็วมาก เบราว์เซอร์สามารถแก้ปัญหารูปทรงเรขาคณิตของกริดได้ในรอบเดียวอย่างมีประสิทธิภาพ
2. การปรับขนาดแบบยืดหยุ่น (Flexible Sizing)
หมวดหมู่นี้เพิ่มความยืดหยุ่น ทำให้ track สามารถปรับตามพื้นที่ว่างได้ มันซับซ้อนกว่าการปรับขนาดแบบคงที่เล็กน้อย แต่ก็ยังได้รับการปรับให้เหมาะสมอย่างมากในเบราว์เซอร์สมัยใหม่
- หน่วยสัดส่วน (`fr`): หน่วย `fr` แทนสัดส่วนของพื้นที่ว่างในคอนเทนเนอร์กริด เพื่อคำนวณหน่วย `fr` เบราว์เซอร์จะลบพื้นที่ที่ถูกใช้โดย track ที่ไม่ยืดหยุ่นทั้งหมด (เช่น `px` หรือ `auto`) ก่อน จากนั้นจึงหารพื้นที่ที่เหลือให้กับ track ที่เป็น `fr` ตามสัดส่วนของมัน
โปรไฟล์ประสิทธิภาพ: การคำนวณหน่วย `fr` เป็นกระบวนการหลายขั้นตอน แต่มันเป็นการดำเนินการทางคณิตศาสตร์ที่กำหนดไว้อย่างดีและไม่ขึ้นอยู่กับเนื้อหาของ grid item สำหรับกรณีการใช้งานส่วนใหญ่ มันมีประสิทธิภาพสูงมาก
3. การปรับขนาดตามเนื้อหา (จุดร้อนด้านประสิทธิภาพ)
นี่คือจุดที่น่าสนใจและอาจจะช้าได้ คำสำคัญในการปรับขนาดตามเนื้อหาจะสั่งให้เบราว์เซอร์ปรับขนาด track ตามเนื้อหาของ item ที่อยู่ภายใน สิ่งนี้สร้างความเชื่อมโยงที่ทรงพลังระหว่างเนื้อหาและเลย์เอาต์ แต่ก็มาพร้อมกับต้นทุนในการคำนวณ
- `min-content`: หมายถึงความกว้างขั้นต่ำที่แท้จริงของเนื้อหา สำหรับข้อความ นี่คือความกว้างของคำที่ยาวที่สุดหรือสตริงที่ไม่สามารถตัดคำได้ ในการคำนวณสิ่งนี้ layout engine ของเบราว์เซอร์จะต้องลองจัดวางเนื้อหาเพื่อหาส่วนที่กว้างที่สุดนั้น
- `max-content`: หมายถึงความกว้างที่ต้องการตามปกติของเนื้อหา ซึ่งเป็นความกว้างที่จะใช้หากไม่มีการตัดบรรทัดนอกเหนือจากที่ระบุไว้อย่างชัดเจน ในการคำนวณสิ่งนี้ เบราว์เซอร์จะต้องลองจัดวางเนื้อหาทั้งหมดในบรรทัดเดียวที่ยาวไม่สิ้นสุด
- `auto`: คำสำคัญนี้ขึ้นอยู่กับบริบท เมื่อใช้ในการปรับขนาด track ของกริด โดยทั่วไปจะทำงานเหมือน `max-content` เว้นแต่ item นั้นจะถูกยืดหรือมีขนาดที่ระบุไว้ ความซับซ้อนของมันคล้ายกับ `max-content` เพราะเบราว์เซอร์มักจะต้องวัดเนื้อหาเพื่อกำหนดขนาดของมัน
โปรไฟล์ประสิทธิภาพ: คำสำคัญเหล่านี้มีต้นทุนการคำนวณสูงที่สุด ทำไม? เพราะมันสร้างการพึ่งพากันสองทาง เลย์เอาต์ของคอนเทนเนอร์ขึ้นอยู่กับขนาดของเนื้อหาของ item แต่เลย์เอาต์ของเนื้อหาของ item ก็อาจขึ้นอยู่กับขนาดของคอนเทนเนอร์เช่นกัน เพื่อแก้ไขปัญหานี้ เบราว์เซอร์อาจต้องทำการคำนวณ layout หลายรอบ มันต้องวัดเนื้อหาของทุก item ใน track นั้นก่อนที่จะสามารถเริ่มคำนวณขนาดสุดท้ายของ track เองได้ สำหรับกริดที่มี item จำนวนมาก สิ่งนี้อาจกลายเป็นคอขวดที่สำคัญได้
4. การปรับขนาดโดยใช้ฟังก์ชัน (Function-Based Sizing)
ฟังก์ชันเป็นวิธีที่รวมโมเดลการปรับขนาดที่แตกต่างกันเข้าไว้ด้วยกัน ซึ่งให้ทั้งความยืดหยุ่นและการควบคุม
- `minmax(min, max)`: ฟังก์ชันนี้กำหนดช่วงของขนาด ประสิทธิภาพของ `minmax()` ขึ้นอยู่กับหน่วยที่ใช้สำหรับอาร์กิวเมนต์ของมันโดยสิ้นเชิง `minmax(200px, 1fr)` มีประสิทธิภาพสูงมาก เนื่องจากเป็นการรวมค่าคงที่เข้ากับค่าที่ยืดหยุ่นได้ อย่างไรก็ตาม `minmax(min-content, 500px)` จะได้รับต้นทุนด้านประสิทธิภาพของ `min-content` มาด้วย เพราะเบราว์เซอร์ยังคงต้องคำนวณมันเพื่อดูว่ามันใหญ่กว่าค่าสูงสุดหรือไม่
- `fit-content(value)`: นี่คือการจำกัดค่า (clamp) อย่างหนึ่ง มันเทียบเท่ากับ `minmax(auto, max-content)` แต่ถูกจำกัดไว้ที่ `value` ที่กำหนด ดังนั้น `fit-content(300px)` จะทำงานเหมือน `minmax(min-content, max(min-content, 300px))` และมันก็มีต้นทุนด้านประสิทธิภาพของการปรับขนาดตามเนื้อหาเช่นกัน
เครื่องมือสำคัญ: การวิเคราะห์ประสิทธิภาพด้วย Chrome DevTools
ทฤษฎีนั้นมีประโยชน์ แต่ข้อมูลคือสิ่งที่ยืนยันได้จริง เพื่อทำความเข้าใจว่าเลย์เอาต์กริดของคุณทำงานอย่างไรในโลกแห่งความเป็นจริง คุณต้องทำการวัดผล พาเนล Performance ใน DevTools ของ Google Chrome เป็นเครื่องมือที่ขาดไม่ได้สำหรับเรื่องนี้
วิธีบันทึกโปรไฟล์ประสิทธิภาพ
ทำตามขั้นตอนเหล่านี้เพื่อเก็บข้อมูลที่คุณต้องการ:
- เปิดหน้าเว็บของคุณใน Chrome
- เปิด DevTools (F12, Ctrl+Shift+I, หรือ Cmd+Opt+I)
- ไปที่แท็บ Performance
- ตรวจสอบให้แน่ใจว่าได้ติ๊กช่อง "Web Vitals" เพื่อรับเครื่องหมายที่เป็นประโยชน์บนไทม์ไลน์ของคุณ
- คลิกปุ่ม Record (วงกลม) หรือกด Ctrl+E
- ดำเนินการที่คุณต้องการวิเคราะห์ ซึ่งอาจเป็นการโหลดหน้าเว็บครั้งแรก, การปรับขนาดหน้าต่างเบราว์เซอร์, หรือการกระทำที่เพิ่มเนื้อหาลงในกริดแบบไดนามิก (เช่น การใช้ตัวกรอง) การกระทำเหล่านี้ล้วนเป็นการกระทำที่กระตุ้นให้เกิดการคำนวณ layout
- คลิก Stop หรือกด Ctrl+E อีกครั้ง
- DevTools จะประมวลผลข้อมูลและแสดงไทม์ไลน์โดยละเอียดให้คุณ
การวิเคราะห์ Flame Chart
Flame chart คือการแสดงผลข้อมูลหลักของการบันทึกของคุณ สำหรับการวิเคราะห์เลย์เอาต์ คุณจะต้องเน้นไปที่ส่วน "Main" thread
มองหาแถบสีม่วงยาวๆ ที่มีป้ายกำกับว่า "Rendering" ภายในแถบเหล่านี้ คุณจะพบเหตุการณ์สีม่วงเข้มที่มีป้ายกำกับว่า "Layout" นี่คือช่วงเวลาเฉพาะที่เบราว์เซอร์กำลังคำนวณรูปทรงเรขาคณิตของหน้าเว็บ
- Layout Tasks ที่ยาวนาน: บล็อก 'Layout' ที่ยาวเพียงบล็อกเดียวถือเป็นสัญญาณอันตราย วางเมาส์เหนือมันเพื่อดูระยะเวลาของมัน งาน layout ใดๆ ที่ใช้เวลามากกว่าสองสามมิลลิวินาที (เช่น > 10-15ms) บนเครื่องที่มีประสิทธิภาพสูง ควรได้รับการตรวจสอบ เนื่องจากมันจะช้ากว่ามากบนอุปกรณ์ที่มีประสิทธิภาพน้อยกว่า
- Layout Thrashing: มองหาเหตุการณ์ 'Layout' เล็กๆ จำนวนมากที่เกิดขึ้นอย่างรวดเร็วต่อเนื่องกัน ซึ่งมักจะสลับกับเหตุการณ์ JavaScript ('Scripting') รูปแบบนี้เรียกว่า layout thrashing เกิดขึ้นเมื่อ JavaScript อ่านคุณสมบัติทางเรขาคณิตซ้ำๆ (เช่น `offsetHeight`) แล้วเขียนสไตล์ที่ทำให้มันไม่ถูกต้อง ซึ่งบังคับให้เบราว์เซอร์ต้องคำนวณ layout ใหม่ซ้ำแล้วซ้ำเล่าในลูป
การใช้แท็บ Summary และ Performance Monitor
- แท็บ Summary: หลังจากเลือกช่วงเวลาใน flame chart แล้ว แท็บ Summary ที่ด้านล่างจะแสดงแผนภูมิวงกลมที่แบ่งเวลาที่ใช้ไป ให้ความสนใจเป็นพิเศษกับเปอร์เซ็นต์ของ "Rendering" และโดยเฉพาะ "Layout"
- Performance Monitor: สำหรับการวิเคราะห์แบบเรียลไทม์ ให้เปิด Performance Monitor (จากเมนู DevTools: More tools > Performance monitor) ซึ่งจะให้กราฟสดสำหรับการใช้งาน CPU, ขนาดฮีป JS, โหนด DOM และที่สำคัญคือ Layouts/sec การโต้ตอบกับหน้าเว็บของคุณและดูกราฟนี้พุ่งสูงขึ้นสามารถบอกคุณได้ทันทีว่าการกระทำใดที่กระตุ้นให้เกิดการคำนวณ layout ที่มีค่าใช้จ่ายสูง
สถานการณ์การวิเคราะห์เชิงปฏิบัติ: จากทฤษฎีสู่การปฏิบัติ
มาทดสอบความรู้ของเราด้วยตัวอย่างเชิงปฏิบัติกัน เราจะเปรียบเทียบการใช้งานกริดที่แตกต่างกันและวิเคราะห์โปรไฟล์ประสิทธิภาพตามสมมติฐาน
สถานการณ์ที่ 1: แบบคงที่และยืดหยุ่น (`px` และ `fr`) เทียบกับแบบอิงตามเนื้อหา (`auto`)
ลองนึกภาพกริดสินค้าที่มี 100 รายการ มาเปรียบเทียบสองแนวทางสำหรับคอลัมน์กัน
แนวทาง A (ประสิทธิภาพสูง): ใช้ `minmax()` กับค่าต่ำสุดแบบคงที่และค่าสูงสุดแบบยืดหยุ่น
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
แนวทาง B (อาจจะช้า): ใช้ `auto` หรือ `max-content` เพื่อให้เนื้อหากำหนดขนาดคอลัมน์
grid-template-columns: repeat(auto-fill, minmax(auto, 300px));
การวิเคราะห์:
- ในแนวทาง A งานของเบราว์เซอร์นั้นง่าย มันรู้ว่าความกว้างขั้นต่ำของแต่ละรายการคือ 250px มันสามารถคำนวณได้อย่างรวดเร็วว่ามีกี่รายการที่พอดีกับความกว้างของคอนเทนเนอร์ แล้วจึงกระจายพื้นที่ที่เหลือให้กับรายการเหล่านั้น นี่เป็นแนวทางการปรับขนาดจากภายนอก (extrinsic) ที่รวดเร็วซึ่งคอนเทนเนอร์เป็นผู้ควบคุม งาน Layout ในโปรไฟล์ประสิทธิภาพจะสั้นมาก
- ในแนวทาง B เบราว์เซอร์มีงานที่ยากกว่ามาก คำสำคัญ `auto` (ในบริบทนี้ มักจะถูกแปลงเป็น `max-content`) หมายความว่าในการกำหนดความกว้างของคอลัมน์เดียว เบราว์เซอร์จะต้องเรนเดอร์เนื้อหาของการ์ดสินค้าทั้ง 100 ใบในเชิงสมมติฐานก่อนเพื่อหาความกว้าง `max-content` ของมัน จากนั้นจึงใช้ค่าที่วัดได้นี้ในอัลกอริทึมการแก้กริด แนวทางการปรับขนาดจากภายใน (intrinsic) นี้ต้องการงานวัดผลล่วงหน้าจำนวนมหาศาลก่อนที่จะสามารถกำหนดเลย์เอาต์สุดท้ายได้ งาน Layout ในโปรไฟล์ประสิทธิภาพจะยาวนานกว่าอย่างมีนัยสำคัญ ซึ่งอาจยาวนานกว่าเป็นสิบเท่า
สถานการณ์ที่ 2: ต้นทุนของกริดที่ซ้อนกันหลายชั้น (Deeply Nested Grids)
ปัญหาด้านประสิทธิภาพของกริดสามารถทวีความรุนแรงขึ้นได้ ลองพิจารณาเลย์เอาต์ที่กริดแม่ใช้การปรับขนาดตามเนื้อหา และลูกๆ ของมันก็เป็นกริดที่ซับซ้อนเช่นกัน
ตัวอย่าง:
เลย์เอาต์หน้าหลักเป็นกริดสองคอลัมน์: `grid-template-columns: max-content 1fr;` คอลัมน์แรกเป็นแถบด้านข้าง (sidebar) ที่มีวิดเจ็ตต่างๆ หนึ่งในวิดเจ็ตเหล่านั้นคือปฏิทิน ซึ่งสร้างขึ้นด้วย CSS Grid เช่นกัน
การวิเคราะห์:
Layout engine ของเบราว์เซอร์ต้องเผชิญกับห่วงโซ่การพึ่งพาที่ท้าทาย:
- เพื่อแก้ไขคอลัมน์ `max-content` ของหน้าหลัก มันต้องคำนวณความกว้าง `max-content` ของแถบด้านข้าง
- เพื่อคำนวณความกว้างของแถบด้านข้าง มันต้องคำนวณความกว้างของลูกๆ ทั้งหมด รวมถึงวิดเจ็ตปฏิทิน
- เพื่อคำนวณความกว้างของวิดเจ็ตปฏิทิน มันต้องแก้ไขเลย์เอาต์กริดภายในของมันเอง
การคำนวณสำหรับแม่จะถูกบล็อกจนกว่าเลย์เอาต์ของลูกจะได้รับการแก้ไขอย่างสมบูรณ์ การเชื่อมโยงที่ลึกซึ้งนี้อาจนำไปสู่เวลาในการคำนวณ layout ที่ยาวนานอย่างน่าประหลาดใจ หากกริดลูกใช้การปรับขนาดตามเนื้อหาด้วย ปัญหาก็จะยิ่งแย่ลง การวิเคราะห์หน้าเว็บดังกล่าวมีแนวโน้มที่จะเปิดเผยงาน 'Layout' ที่ยาวนานมากเพียงงานเดียวในระหว่างการเรนเดอร์ครั้งแรก
กลยุทธ์การปรับปรุงประสิทธิภาพและแนวทางปฏิบัติที่ดีที่สุด
จากการวิเคราะห์ของเรา เราสามารถสรุปกลยุทธ์ที่นำไปปฏิบัติได้หลายอย่างสำหรับการสร้างเลย์เอาต์กริดที่มีประสิทธิภาพสูง
1. ควรใช้การปรับขนาดจากภายนอก (Extrinsic Sizing) มากกว่าการปรับขนาดจากภายใน (Intrinsic Sizing)
นี่คือกฎทองของประสิทธิภาพกริด เมื่อใดก็ตามที่เป็นไปได้ ให้คอนเทนเนอร์กริดเป็นผู้กำหนดขนาดของ track โดยใช้หน่วยเช่น `px`, `rem`, `%` และ `fr` สิ่งนี้จะให้ชุดข้อจำกัดที่ชัดเจนและคาดเดาได้แก่ layout engine ของเบราว์เซอร์ ซึ่งส่งผลให้การคำนวณเร็วขึ้น
แทนที่จะใช้แบบนี้ (Intrinsic):
grid-template-columns: repeat(auto-fit, max-content);
ควรใช้แบบนี้ (Extrinsic):
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
2. จำกัดขอบเขตของการปรับขนาดตามเนื้อหา
มีกรณีการใช้งานที่ถูกต้องสำหรับ `min-content` และ `max-content` เช่น สำหรับเมนูดรอปดาวน์หรือป้ายกำกับข้างฟิลด์ฟอร์ม เมื่อคุณต้องใช้มัน พยายามจำกัดผลกระทบของมัน:
- ใช้กับ track ไม่กี่อัน: ใช้มันกับคอลัมน์หรือแถวเดียว ไม่ใช่กับรูปแบบที่ซ้ำกันซึ่งมีไอเท็มหลายร้อยรายการ
- จำกัดคอนเทนเนอร์แม่: วางกริดที่ใช้การปรับขนาดตามเนื้อหาไว้ในคอนเทนเนอร์ที่มี `max-width` สิ่งนี้จะให้ขอบเขตแก่ layout engine ซึ่งบางครั้งสามารถช่วยให้มันปรับปรุงการคำนวณได้
- ใช้ร่วมกับ `minmax()`: ให้ค่าต่ำสุดหรือสูงสุดที่เหมาะสมควบคู่ไปกับคำสำคัญตามเนื้อหา เช่น `minmax(200px, max-content)` สิ่งนี้สามารถช่วยให้เบราว์เซอร์เริ่มต้นการคำนวณได้เร็วขึ้น
3. ทำความเข้าใจและใช้ `subgrid` อย่างชาญฉลาด
`subgrid` เป็นฟีเจอร์ที่ทรงพลังที่ช่วยให้กริดที่ซ้อนกันสามารถใช้คำจำกัดความของ track ของกริดแม่ได้ ซึ่งยอดเยี่ยมสำหรับการจัดตำแหน่ง
ผลกระทบด้านประสิทธิภาพ: `subgrid` อาจเป็นดาบสองคม ในแง่หนึ่ง มันเพิ่มความเชื่อมโยงระหว่างการคำนวณเลย์เอาต์ของแม่และลูก ซึ่งในทางทฤษฎีอาจทำให้การแก้เลย์เอาต์ที่ซับซ้อนในตอนแรกช้าลง ในทางกลับกัน ด้วยการทำให้แน่ใจว่าไอเท็มต่างๆ ถูกจัดตำแหน่งอย่างสมบูรณ์แบบตั้งแต่ต้น มันสามารถป้องกันการเลื่อนของเลย์เอาต์ (layout shifts) และ reflow ที่อาจเกิดขึ้นในภายหลังหากคุณพยายามเลียนแบบการจัดตำแหน่งด้วยตนเองด้วยวิธีอื่น คำแนะนำที่ดีที่สุดคือการวิเคราะห์ หากคุณมีเลย์เอาต์ที่ซ้อนกันซับซ้อน ให้วัดประสิทธิภาพของมันทั้งที่มีและไม่มี `subgrid` เพื่อดูว่าแบบไหนดีกว่าสำหรับกรณีการใช้งานเฉพาะของคุณ
4. Virtualization: ทางออกที่ดีที่สุดสำหรับชุดข้อมูลขนาดใหญ่
หากคุณกำลังสร้างกริดที่มีไอเท็มหลายร้อยหรือหลายพันรายการ (เช่น ตารางข้อมูล, แกลเลอรีรูปภาพที่เลื่อนได้ไม่สิ้นสุด) การปรับแต่ง CSS เพียงอย่างเดียวจะไม่สามารถเอาชนะปัญหาพื้นฐานได้: เบราว์เซอร์ยังคงต้องคำนวณเลย์เอาต์สำหรับทุกองค์ประกอบ
ทางออกคือ virtualization (หรือ 'windowing') นี่เป็นเทคนิคที่ใช้ JavaScript ซึ่งคุณจะเรนเดอร์เฉพาะองค์ประกอบ DOM เพียงไม่กี่ชิ้นที่มองเห็นได้ใน viewport ในขณะนั้น เมื่อผู้ใช้เลื่อน คุณจะใช้โหนด DOM เหล่านี้ซ้ำและแทนที่เนื้อหาของมัน สิ่งนี้จะทำให้จำนวนองค์ประกอบที่เบราว์เซอร์ต้องจัดการระหว่างการคำนวณเลย์เอาต์มีขนาดเล็กและคงที่ ไม่ว่าชุดข้อมูลของคุณจะมี 100 หรือ 100,000 รายการก็ตาม
ไลบรารีอย่าง `react-window` และ `tanstack-virtual` ให้การใช้งานรูปแบบนี้ที่แข็งแกร่ง สำหรับกริดขนาดใหญ่จริงๆ นี่คือการปรับปรุงประสิทธิภาพที่มีประสิทธิภาพที่สุดที่คุณสามารถทำได้
กรณีศึกษา: การปรับปรุงประสิทธิภาพกริดแสดงรายการสินค้า
ลองมาดูสถานการณ์การปรับปรุงประสิทธิภาพที่สมจริงสำหรับเว็บไซต์อีคอมเมิร์ซระดับโลก
ปัญหา: หน้าแสดงรายการสินค้ารู้สึกอืด เมื่อปรับขนาดหน้าต่างเบราว์เซอร์หรือใช้ตัวกรอง จะมีความล่าช้าที่สังเกตได้ก่อนที่สินค้าจะจัดเรียงใหม่ในตำแหน่งใหม่ คะแนน Core Web Vitals สำหรับ Interaction to Next Paint (INP) ไม่ดี
โค้ดเริ่มต้น (สถานะ "ก่อน"):
กริดถูกกำหนดให้มีความยืดหยุ่นสูง ทำให้การ์ดสินค้าสามารถกำหนดความกว้างของคอลัมน์ตามเนื้อหาของมันได้ (เช่น ชื่อสินค้าที่ยาว)
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, fit-content(320px));
gap: 1rem;
}
การวิเคราะห์ประสิทธิภาพ:
- เราบันทึกโปรไฟล์ประสิทธิภาพขณะปรับขนาดหน้าต่างเบราว์เซอร์
- Flame chart แสดงงาน 'Layout' ที่ยาวและเกิดซ้ำทุกครั้งที่เหตุการณ์ resize เกิดขึ้น โดยใช้เวลามากกว่า 80ms บนอุปกรณ์โดยเฉลี่ย
- ฟังก์ชัน `fit-content()` อาศัยการคำนวณ `min-content` และ `max-content` ตัววิเคราะห์ยืนยันว่าในแต่ละการปรับขนาด เบราว์เซอร์กำลังวัดเนื้อหาของการ์ดสินค้าที่มองเห็นทั้งหมดใหม่อย่างบ้าคลั่งเพื่อคำนวณโครงสร้างกริดใหม่ นี่คือที่มาของความล่าช้า
วิธีแก้ไข (สถานะ "หลัง"):
เราเปลี่ยนจากโมเดลการปรับขนาดตามเนื้อหา (intrinsic) มาเป็นโมเดลที่กำหนดโดยคอนเทนเนอร์ (extrinsic) เรากำหนดขนาดขั้นต่ำที่แน่นอนให้กับการ์ดและปล่อยให้มันยืดหยุ่นได้ถึงสัดส่วนของพื้นที่ว่าง
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1rem;
}
ภายใน CSS ของการ์ดสินค้า เราเพิ่มกฎเพื่อจัดการเนื้อหาที่อาจยาวเกินไปอย่างสวยงามภายในคอนเทนเนอร์ใหม่ที่เข้มงวดกว่า:
.product-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
ผลลัพธ์:
- เราบันทึกโปรไฟล์ประสิทธิภาพใหม่ขณะปรับขนาด
- ตอนนี้ Flame chart แสดงว่างาน 'Layout' สั้นอย่างไม่น่าเชื่อ โดยสม่ำเสมอต่ำกว่า 5ms
- เบราว์เซอร์ไม่จำเป็นต้องวัดเนื้อหาอีกต่อไป มันทำการคำนวณทางคณิตศาสตร์อย่างง่ายโดยอิงจากความกว้างของคอนเทนเนอร์และค่าต่ำสุด `280px`
- ประสบการณ์ผู้ใช้เปลี่ยนไป การปรับขนาดราบรื่นและทันที การใช้ตัวกรองรู้สึกรวดเร็วเพราะเบราว์เซอร์สามารถคำนวณเลย์เอาต์ใหม่ได้เกือบจะในทันที
หมายเหตุเกี่ยวกับเครื่องมือข้ามเบราว์เซอร์
แม้ว่าคู่มือนี้จะเน้นที่ Chrome DevTools แต่สิ่งสำคัญคือต้องจำไว้ว่าผู้ใช้มีความชอบเบราว์เซอร์ที่หลากหลาย เครื่องมือสำหรับนักพัฒนาของ Firefox มีพาเนล Performance ที่ยอดเยี่ยม (มักเรียกว่า 'Profiler') ซึ่งให้ flame charts และความสามารถในการวิเคราะห์ที่คล้ายกัน Web Inspector ของ Safari ก็มีแท็บ 'Timelines' ที่ทรงพลังสำหรับการวิเคราะห์ประสิทธิภาพการเรนเดอร์เช่นกัน ควรทดสอบการปรับปรุงประสิทธิภาพของคุณบนเบราว์เซอร์หลักๆ เสมอ เพื่อให้แน่ใจว่าผู้ใช้ทั่วโลกของคุณจะได้รับประสบการณ์ที่มีคุณภาพสูงและสอดคล้องกัน
สรุป: การสร้างกริดประสิทธิภาพสูงโดยการออกแบบ
CSS Grid เป็นเครื่องมือที่ทรงพลังอย่างยิ่ง แต่ฟีเจอร์ที่ล้ำหน้าที่สุดของมันก็ไม่ได้มาโดยไม่มีต้นทุนในการคำนวณ ในฐานะผู้เชี่ยวชาญด้านเว็บที่พัฒนาเพื่อผู้ชมทั่วโลกด้วยอุปกรณ์และสภาพเครือข่ายที่หลากหลาย เราต้องคำนึงถึงประสิทธิภาพตั้งแต่เริ่มต้นกระบวนการพัฒนา
ประเด็นสำคัญที่ชัดเจนคือ:
- Layout คือคอขวดด้านประสิทธิภาพ: ขั้นตอน 'Layout' ของการเรนเดอร์อาจมีค่าใช้จ่ายสูง โดยเฉพาะกับระบบที่ซับซ้อนและอิงตามข้อจำกัดเช่น CSS Grid
- กลยุทธ์การปรับขนาดมีความสำคัญ: การปรับขนาดที่กำหนดโดยคอนเทนเนอร์ (extrinsic) (`px`, `fr`, `%`) แทบจะเร็วกว่าการปรับขนาดตามเนื้อหา (intrinsic) (`min-content`, `max-content`, `auto`) เสมอ
- วัดผล อย่าเดา: เครื่องมือวิเคราะห์ประสิทธิภาพของเบราว์เซอร์ไม่ได้มีไว้สำหรับการดีบักเท่านั้น ใช้มันในเชิงรุกเพื่อวิเคราะห์ตัวเลือกเลย์เอาต์ของคุณและตรวจสอบการปรับปรุงประสิทธิภาพของคุณ
- ปรับให้เหมาะสมสำหรับกรณีทั่วไป: สำหรับคอลเลกชันของไอเท็มจำนวนมาก คำจำกัดความของกริดแบบ extrinsic ที่เรียบง่ายจะให้ประสบการณ์ผู้ใช้ที่ดีกว่าแบบที่ซับซ้อนและรับรู้เนื้อหา
ด้วยการรวมการวิเคราะห์ประสิทธิภาพเข้ากับขั้นตอนการทำงานปกติของคุณ คุณสามารถสร้างเลย์เอาต์ที่ซับซ้อน ตอบสนองได้ดี และแข็งแกร่งด้วย CSS Grid โดยมั่นใจได้ว่าไม่เพียงแต่จะสวยงามทางสายตาเท่านั้น แต่ยังรวดเร็วอย่างเหลือเชื่อและเข้าถึงได้สำหรับผู้ใช้ทุกที่